#include "PcManager.h"
#include "Pc.h"
#include "common.h"

#include <string.h>	// declares NULL
#include <stdio.h> // printf
#include <time.h>

#ifdef _WIN32
#ifdef _DEBUG
   #include <crtdbg.h>
   #undef THIS_FILE
   static char THIS_FILE[] = __FILE__;
   #define new       new( _NORMAL_BLOCK, __FILE__, __LINE__)
   #define malloc(s) _malloc_dbg(s, _NORMAL_BLOCK, __FILE__, __LINE__)
#endif
#endif

// Constructor
PcManager::PcManager(Database *db, HANDLE hMutex) {
	// blank out link list of todos
	this->head = NULL;
	// remember a link to the db
	this->db = db;
	// remember a link to the mutex
	this->hMutex = hMutex;

	// initial loading of pc link-list
	this->loadall();
}

// Deconstructor
PcManager::~PcManager() {
	Pc *slider = this->head;
	Pc *tmp;

	// loop through todos freeing each one in turn
	while(slider != NULL) {
		tmp = slider;
		slider = slider->next;

		delete tmp;
	}
}

// load all available pcs
bool PcManager::loadall() {
	MYSQL_RES *rSelect;
	MYSQL_ROW row;
	char query[DEFAULT_BUFLEN];

	sprintf(query, "SELECT id FROM n_wb_pc WHERE style='pc'");

	// -- Thread-Safe Mysql call --
	rSelect = db->threadsafe_query(hMutex, query);

	if(rSelect) {
		while((row = mysql_fetch_row(rSelect))) {
			// load up this id
			this->load(atoi(row[0]));
		}
		// free up the result from the mysql query
		mysql_free_result(rSelect);
	}

	return true;
}

// Load up Pc node using id from database
Pc* PcManager::load(int id) {
	Pc *slider;

	// don't add again if already exists
	slider = this->get(id);
	if(slider != NULL) {
		return slider;
	}

	// initialize slider at head
	slider = this->head;

	// this will be the first todo
	if(slider == NULL) {
		this->head = new Pc(id, this->hMutex, &(this->db->conn));
		this->head->prev = NULL;
		this->head->next = NULL;

		slider = this->head;
	}
	// not the first todo, add to end of list
	else {
		// advanced till slider is the last node
		while(slider->next != NULL) {
			slider = slider->next;
		}
		// at end of list, attach new todo
		slider->next = new Pc(id, this->hMutex, &(this->db->conn));
		slider->next->prev = slider;
		slider->next->next = NULL;

		slider = slider->next;
	}

	// set some values
	slider->hMutex = this->hMutex;
	slider->db_link = &(this->db->conn);

	return slider;
}

// add a new Pc
Pc* PcManager::add(char *netbios) {
	MYSQL_RES *rUpdate, *rSelect;
	char query[DEFAULT_BUFLEN];
	MYSQL_ROW row;

	// check to see if already exists, add if not
	sprintf(query, "SELECT id FROM n_wb_pc WHERE name='%s'", netbios);
//	printf("query is '%s'\n", query);

	// -- Thread-Safe Mysql call --
	rSelect = db->threadsafe_query(hMutex, query);

	int insert_id = 0;
	if(rSelect) {
		if(mysql_num_rows(rSelect) != 0) {
			if(row = mysql_fetch_row(rSelect)) {
				insert_id = atoi(row[0]);
			}
		}

		// free up the result from the mysql query
		mysql_free_result(rSelect);
	}

	// pc not found, add
	if(insert_id == 0) {
		sprintf(query, "INSERT INTO n_wb_pc (style, name, isHidden) VALUES ('pc', '%s', 0)", netbios);

		// -- Thread-Safe Mysql call --
		// Request ownership of mutex
		WaitForSingleObject(this->hMutex, INFINITE);
		// Make mysql calls which need Mutex protection
		mysql_query(&(this->db->conn), query);
		rUpdate = mysql_store_result(&(this->db->conn));
		// obtain insert id
		insert_id = mysql_insert_id(&(this->db->conn));
		// Release the mutex
		ReleaseMutex(this->hMutex);
		// free up the result from the mysql query
		mysql_free_result(rUpdate);

		sprintf(query, "CREATE TABLE IF NOT EXISTS n_wb_pc_%d (", insert_id);
		strcat(query, "id INT NOT NULL AUTO_INCREMENT PRIMARY KEY");
		strcat(query, ", record VARCHAR(256)");
		strcat(query, ")");
		printf("insert_id = %d\n", insert_id);

		// -- Thread-Safe Mysql call --
		rUpdate = db->threadsafe_query(hMutex, query);
		// free up the result from the mysql query
		mysql_free_result(rUpdate);
	}

	// Update dt_access
	time_t rawtime;
	struct tm * timeinfo;
	time ( &rawtime );
	timeinfo = localtime ( &rawtime );
	char timestamp[DEFAULT_BUFLEN];
	strftime(timestamp, DEFAULT_BUFLEN, "%Y-%m-%d %H:%m:%S", timeinfo);

	sprintf(query, "UPDATE n_wb_pc SET dt_access='%s', isHidden=0 WHERE id=%d", timestamp, insert_id);
	printf("query = '%s'\n", query);

	// -- Thread-Safe Mysql call --
	rUpdate = db->threadsafe_query(hMutex, query);
	// free up the result from the mysql query
	mysql_free_result(rUpdate);

	// load up a node representing this new pc
	// then go ahead and return in case its needed
	return this->load(insert_id);
}

// del a Pc node by the specified id
bool PcManager::del(int id) {
	Pc *slider = this->head;

	if(slider == NULL) {
		return false;
	}

	while(slider != NULL) {
		if(slider->id == id) {
			break;
		}
		slider = slider->next;
	}

	if(slider == NULL) {
		return false;
	}

	if(slider == this->head) {
		this->head = slider->next;
		if(this->head != NULL) {
			this->head->prev = NULL;
		}
	}
	else {
		if(slider->prev != NULL) {
			slider->prev->next = slider->next;
		}
		if(slider->next != NULL) {
			slider->next->prev = slider->prev;
		}
	}

	delete slider;

	printf("PCM: del pc\n");
	MYSQL_RES *rUpdate;
	char query[DEFAULT_BUFLEN];
	sprintf(query, "UPDATE n_wb_pc SET isHidden=1 WHERE id=%d", id);

	// -- Thread-Safe Mysql call --
	rUpdate = db->threadsafe_query(hMutex, query);
	// free up the result from the mysql query
	mysql_free_result(rUpdate);

	return true;
}

// del a Pc node by the specified id
bool PcManager::del(char *netbios) {
	Pc *slider = this->head;

	if(slider == NULL) {
		return false;
	}

	while(slider != NULL) {
		if(!strcmp(slider->netbios, netbios)) {
			break;
		}
		slider = slider->next;
	}

	if(slider == NULL) {
		return false;
	}

	// remember the pc id
	int id = slider->id;

	if(slider == this->head) {
		this->head = slider->next;
		if(this->head != NULL) {
			this->head->prev = NULL;
		}
	}
	else {
		if(slider->prev != NULL) {
			slider->prev->next = slider->next;
		}
		if(slider->next != NULL) {
			slider->next->prev = slider->prev;
		}
	}

	delete slider;

	printf("PCM: del pc\n");
	MYSQL_RES *rUpdate;
	char query[DEFAULT_BUFLEN];
	sprintf(query, "UPDATE n_wb_pc SET isHidden=1 WHERE id=%d", id);

	// -- Thread-Safe Mysql call --
	rUpdate = db->threadsafe_query(hMutex, query);
	// free up the result from the mysql query
	mysql_free_result(rUpdate);

	return true;
}

// get a pointer to a pc by the id
Pc* PcManager::get(int id) {
	Pc *slider = this->head;

	// loop through each todo
	while(slider != NULL) {
		// check if this is the todo we are looking for
		if(slider->id == id) {
			return slider;
		}

		// advanced till slider to next node
		slider = slider->next;
	}

	return NULL;
}

// get a pointer to a pc by the netbios
Pc* PcManager::get(char *netbios) {
	Pc *slider = this->head;

	// loop through each todo
	while(slider != NULL) {
		// check if this is the todo we are looking for
		if(!strcmp(slider->netbios, netbios)) {
			return slider;
		}

		// advanced till slider to next node
		slider = slider->next;
	}

	return NULL;
}

// set a todo detail
/*
bool PcManager::set(char *id, char *data, char *value) {
	Pc *todo = this->get(id);
	if(todo == NULL) {
		return false;
	}

	// save the detail
	detail.set(data, value);

	return true;
}
*/

// whether there are any active todos left
/*
bool PcManager::isActive() {
	Pc *slider = this->head;

	// loop through each todo
	while(slider != NULL) {
		// check if this is the todo we are looking for
		if(slider->_isActive) {
			return true;
		}

		// advanced till slider to next node
		slider = slider->next;
	}

	return false;
}
*/

/*
// returns a todo ready to be worked on
Pc* PcManager::getReady() {
	Pc *slider = this->head;

//	printf("[PcManager::get]: %d\r\n", id);

	// loop through each todo
	while(slider != NULL) {
		// check if this is the todo we are looking for
		if(slider->status == ACTIVE) {
			return slider;
		}

		// advanced till slider to next node
		slider = slider->next;
	}

	return NULL;
}
*/